#include <iostream>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <fstream>

#define CRLF "\r\n"
#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define HOME_PAGE "index.html"
#define ROOT_PATH "wwwroot"

//GET /a/b/c.html HTTP/1.1
std::string getPath(std::string http_request)
{
    //这里忘写了！！！
    std::size_t pos=http_request.find(CRLF);
    if(pos==std::string::npos)    return "";
    std::string http_line=http_request.substr(0,pos);

    std::size_t first=http_line.find(SPACE);
    if(first==std::string::npos)    return "";
    std::size_t second=http_line.rfind(SPACE);
    if(second==std::string::npos)    return "";
    std::string path=http_line.substr(first+SPACE_LEN,second-(first+SPACE_LEN));
    if(path=="/"&&path.size()==1)   path+=HOME_PAGE;
    return path;
}
std::string readFile(const std::string& resource)
{
    std::ifstream in(resource, std::ifstream::binary);
    if(!in.is_open())   return "404";
    std::string content;
    std::string line;
    while(getline(in,line)) content+=line;
    return content;
}
void handlerHttpRequest(int sock)
{
    //std::cout << "2222222222222" << std::endl;
    char buf[1024];
    ssize_t s = read(sock, buf, sizeof(buf) - 1);
    if (s <= 0)
    {
        exit(0);
    }
    std::cout << buf << std::endl;
    std::string path=getPath(buf);// /a/b/c.html
    std::string resource=ROOT_PATH;
    resource+=path;
    std::cout<<"resource: "<<resource<<std::endl;//wwwroot/index.html
    std::string html=readFile(resource);
    std::string response="HTTP/1.0 200 OK\r\n";//响应行  响应报头    空行    正文
    //响应报头
    response+="Content-Type:text/html\r\n";
    response+=("Content-Length:"+std::to_string(html.size())+"\r\n");
    //空行
    response+="\r\n";
    //正文
    response+=html;
    //发送
    send(sock,response.c_str(),response.size(),0);
}

class ServerTcp
{
public:
    ServerTcp(uint16_t port, std::string ip = "") : port_(port), ip_(ip), listenSock_(-1)
    {
    }
    void init()
    {
        // 1.创建套接字
        listenSock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenSock_ <= 0)
        {
            std::cerr << "socket create error" << std::endl;
            exit(1);
        }
        // 2.填写套接字信息
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 3.bind
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof local) < 0)
        {
            std::cerr << "bind error" << std::endl;
            exit(2);
        }
        // 4.listen
        if (listen(listenSock_, 5) < 0)
        {
            std::cerr << "listen error" << std::endl;
            exit(3);
        }
    }
    void loop()
    {
        while (true)
        {
            //std::cout << listenSock_ << std::endl;
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            int serverSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (serverSock < 0)
            {
                std::cerr << "accept error" << std::endl;
                // continue; // 接客失败不怎么样，重新接客就行
                exit(6);
            }
            //std::cout << "11111111111111" << std::endl;
            pid_t id = fork();
            if (id == 0) // 子进程
            {
                close(listenSock_);
                if (fork() > 0)
                    exit(4);
    //std::cout << "3333333333333" << std::endl;
                handlerHttpRequest(serverSock); 
    //std::cout << "44444444444" << std::endl;
                exit(0);
            }
            close(serverSock);
            waitpid(id, nullptr, 0);
            // 主进程
        }
    }

private:
    int listenSock_;
    uint16_t port_;
    std::string ip_;
};